package com.fastloan.mgt.application.approve.service.impl;

import com.fastloan.common.BasicServiceImpl;
import com.fastloan.mgt.application.approve.dao.ApplicationApproveTemplateMapper;
import com.fastloan.mgt.application.approve.expection.ApproveException;
import com.fastloan.mgt.application.approve.model.ApplicationApproveTemplate;
import com.fastloan.mgt.application.approve.service.ApplicationApproveService;
import com.fastloan.mgt.application.approve.service.ApplicationApproveTemplateService;
import com.fastloan.mgt.application.base.model.Application;
import com.fastloan.mgt.application.base.service.ApplicationService;
import com.fastloan.mgt.expert.dao.ExpertMapper;
import com.fastloan.mgt.expert.model.vo.ExpertVO;
import com.fastloan.mgt.expert.service.ExpertProductService;
import com.fastloan.mgt.processcontrol.base.annotation.FunctionHandlerClass;
import com.fastloan.mgt.processcontrol.base.annotation.FunctionHandlerMethod;
import com.fastloan.mgt.processcontrol.base.model.ProcessSession;
import com.fastloan.mgt.processcontrol.base.service.ProcessDispatcher;
import com.fastloan.mgt.product.approve.model.ProductApprove;
import com.fastloan.mgt.product.approve.service.ProductApproveService;
import com.fastloan.mgt.product.basics.model.Product;
import com.fastloan.mgt.product.basics.service.ProductService;
import com.fastloan.mgt.product.flow.enums.ProductFunctionGroup;
import com.fastloan.utils.DroolsAcceptUtil;
import com.fastloan.utils.RandomDataUtil;
import org.apache.commons.lang3.StringUtils;
import org.kie.api.KieBase;
import org.kie.api.cdi.KBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

import static com.fastloan.mgt.application.base.enums.ApplicationStatusEnum.APP_APPROVE;
import static com.fastloan.mgt.product.enums.ProductEnum.PUBLISHED;
import static com.fastloan.mgt.product.enums.ProductEnum.UNPUBLISHED;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

/**
 * @author admins
 * createTime 2017/11/09
 */
@Service
@FunctionHandlerClass(processName = "专家审批", bmpIds = {ProductFunctionGroup.GROUP_ONE})
public class ApplicationApproveTemplateServiceImpl extends BasicServiceImpl<ApplicationApproveTemplate> implements ApplicationApproveTemplateService {
    @Autowired
    private ApplicationApproveTemplateMapper applicationApproveTemplateMapper;

    @Autowired
    private ApplicationApproveService applicationApproveService;

    @Autowired
    private ProductApproveService productApproveService;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private ExpertMapper expertMapper;

    @Autowired
    private ExpertProductService expertProductService;

    @Autowired
    private ProductService productService;

    @KBase("kBase")
    private KieBase kieBase;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @FunctionHandlerMethod
    public void initialize(String processId) throws ApproveException {
        ProcessSession processSession = ProcessDispatcher.getProcessSession(processId);
        String applicationId = processSession.getAttribute("applicationId", String.class);
        startInitialize(applicationId);
    }

    /**
     * 执行审批流程
     *
     * @param applicationId
     * @throws ApproveException
     */
    private void startInitialize(String applicationId) throws ApproveException {
        Application application = applicationService.selectByPrimaryKey(applicationId);
        List<ProductApprove> productApproveList = startDrools(application.getProductId(), applicationId);
        if (productApproveList != null && !productApproveList.isEmpty()) {
            startInitialize(applicationId, application, productApproveList);
        } else {
            ProcessDispatcher.executeEnd(application.getProcessId(), true);
            log.debug("进件申请额度小于产品限定额度, 跳过专家审批流程, 进件id{}", applicationId);
        }
    }

    /**
     * 插入审批信息
     *
     * @param applicationId
     * @param application
     * @param productApproveList
     * @throws ApproveException
     */
    private void startInitialize(String applicationId, Application application, List<ProductApprove> productApproveList) throws ApproveException {
        try {
            ApplicationApproveTemplate applicationApproveTemplate = new ApplicationApproveTemplate();
            applicationApproveTemplate.setApplicationId(applicationId);
            applicationApproveTemplate.setInitiateStatus(UNPUBLISHED.getType());
            List<ApplicationApproveTemplate> approveTemplateList = select(applicationApproveTemplate);
            Product product = productService.selectByPrimaryKey(productApproveList.get(0).getProductId());
            if (approveTemplateList.isEmpty()) {
                approveTemplateList = getApplicationApproveTemplates(applicationId, productApproveList, product.getRandomPerson());
            } else {
                approveTemplateList = setTemp(approveTemplateList);
            }
            applicationApproveTemplateMapper.insertList(approveTemplateList);
            log.info("审批模板插入完成, 进件id:{}", applicationId);
            applicationApproveService.initialize(applicationId);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("插入审批流程失败, 进件id:{}", applicationId);
            throw new ApproveException("插入审批流程失败");
        } finally {
            application.setApplicationStatus(APP_APPROVE.getType());
            applicationService.updateByPrimaryKeySelective(application);
        }
    }

    /**
     * 复制模板信息
     *
     * @param approveTemplateList
     * @return
     */
    private List<ApplicationApproveTemplate> setTemp(List<ApplicationApproveTemplate> approveTemplateList) {
        List<ApplicationApproveTemplate> templateList = approveTemplateList
                .stream()
                .map(approveTemplate -> {
                    ApplicationApproveTemplate approveTemplateFunction = new ApplicationApproveTemplate();
                    approveTemplateFunction.setApplicationId(approveTemplate.getApplicationId());
                    approveTemplateFunction.setApproveStatus(UNPUBLISHED.getType());
                    approveTemplateFunction.setApproveUsers(approveTemplate.getApproveUsers());
                    approveTemplateFunction.setInitiateStatus(UNPUBLISHED.getType());
                    return approveTemplateFunction.setApproveId(approveTemplate.getApproveId());
                }).collect(toList());
        approveTemplateList.forEach(applicationApproveTemplate -> {
            applicationApproveTemplate.setInitiateStatus(PUBLISHED.getType());
            updateByPrimaryKeySelective(applicationApproveTemplate);
        });
        return templateList;
    }

    /**
     * 设置审批模板信息
     *
     * @param applicationId
     * @param productApproveList
     * @param randomPerson
     * @return
     */
    private List<ApplicationApproveTemplate> getApplicationApproveTemplates(String applicationId, List<ProductApprove> productApproveList, int randomPerson) {
        return productApproveList.stream()
                .map(productApprove -> {
                    ApplicationApproveTemplate applicationApproveTemplate = new ApplicationApproveTemplate();
                    applicationApproveTemplate.setApplicationId(applicationId);
                    applicationApproveTemplate.setApproveStatus(UNPUBLISHED.getType());
                    if (randomPerson == 0) {
                        //指定分件
                        applicationApproveTemplate.setApproveUsers(productApprove.getApproveUsers());
                    } else {
                        //随机分件
                        applicationApproveTemplate.setApproveUsers(filtrateExpert(applicationId, productApprove));
                    }
                    return applicationApproveTemplate.setApproveId(productApprove.getApproveId());
                }).collect(toList());
    }

    @Override
    public List<String> queryApproveUserIdByTemplateId(String templateId) {
        return applicationApproveTemplateMapper.queryApproveUserIdByTemplateId(templateId);
    }

    /**
     * 专家筛选规则
     *
     * @param applicationId
     * @param productApprove
     * @return
     */
    private String filtrateExpert(String applicationId, ProductApprove productApprove) {
        Application application = applicationService.selectByPrimaryKey(applicationId);
        Product product = productService.selectByPrimaryKey(application.getProductId());
        List<ExpertVO> expertVOList = expertProductService.queryExpertByProductId(product.getProductId());
        List<ExpertVO> approveApproveExpert = new ArrayList<>();
        KieSession kieSession = kieBase.newKieSession();
        kieSession.insert(application);
        kieSession.setGlobal("expertList", expertVOList);
        kieSession.setGlobal("approveApproveExpertList", approveApproveExpert);
        kieSession.setGlobal("productTempName", product.getProductName());
        DroolsAcceptUtil droolsAccept = new DroolsAcceptUtil("preliminaryScreening");
        kieSession.fireAllRules(droolsAccept);
        kieSession.dispose();
        String approveUserIds = getApproveUserIds(productApprove, !approveApproveExpert.isEmpty() ? approveApproveExpert : expertVOList);
        if (StringUtils.isBlank(approveUserIds)) {
            log.info("未筛选到合适的审批专家, 进件id{}, 产品id{},产品审批id{}", applicationId, productApprove.getProductId(), productApprove.getApproveId());
        }
        return approveUserIds;
    }

    /**
     * 获取审批专家id
     *
     * @param productApprove
     * @param approveApproveExpert
     * @return
     */
    private String getApproveUserIds(ProductApprove productApprove, List<ExpertVO> approveApproveExpert) {
        List<String> expertIds = approveApproveExpert
                .stream()
                .map(ExpertVO::getUserId)
                .collect(toList());
        log.debug("筛选到符合条件的审批专家id{}", expertIds);
        return RandomDataUtil.generateRandomDataNoRepeat(new LinkedHashSet<>()
                , expertMapper.queryExpertApproveCount(expertIds), productApprove.getApproveNumber())
                .stream()
                .distinct()
                .map(ExpertVO::getUserId)
                .collect(joining(","));
    }

    /**
     * 流程创建规则
     *
     * @param productId
     * @param applicationId
     * @return
     */
    private List<ProductApprove> startDrools(String productId, String applicationId) {
        Example example = new Example(ProductApprove.class);
        example.createCriteria().andEqualTo("productId", productId)
                .andEqualTo("status", UNPUBLISHED.getType());
        Application application = applicationService.selectByPrimaryKey(applicationId);
        List<ProductApprove> productApproveList = productApproveService.selectByExample(example);
        KieSession kieSession = kieBase.newKieSession();
        kieSession.insert(application);
        kieSession.setGlobal("productApproveList", productApproveList);
        kieSession.fireAllRules();
        kieSession.dispose();
        log.debug("执行流程规则, 产品id:{}, 进件id:{}, 操作时间{}", productId, applicationId, LocalDateTime.now());
        return productApproveList;
    }

}

